using System;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace InfoJetSoft.Service.Util
{
	/// <summary>
	/// Summary description for SetupAPIExtractor.
	/// </summary>
	class SetupAPIExtractor
	{
		private string cabPath = null;
		private string targetPath = null;

		public string CabPath 
		{
			set
			{
				this.cabPath = value;
			}
		}

		public string TargetPath
		{
			set
			{
				if( value.EndsWith( "\\" ) || value.EndsWith( "/" ) )
				{
					this.targetPath = value;
				}
				else
				{
					this.targetPath = value + "\\";
				}
			}
		}

		public void Extract()
		{
			PSP_FILE_CALLBACK callBack = new PSP_FILE_CALLBACK(this.IteratorCabinetCallBack);
			uint setupIterateCabinetAction = (uint)SetupIterateCabinetAction.Iterate;
			if (!SetupIterateCabinet(this.cabPath, 0, callBack, setupIterateCabinetAction))
			{
				string message = new Win32Exception((int)GetLastError()).Message;
				throw new InfoJetException( "Error while extracting " + this.cabPath + ": " + message, "SAPIE01" );
			}	
		}
		
		private uint IteratorCabinetCallBack(uint context, uint notification, IntPtr param1, IntPtr param2)
		{
			uint returnValue = NO_ERROR;
			if( notification == SPFILENOTIFY_FILEINCABINET )
			{
				FILE_IN_CABINET_INFO fileInCabinetInfo = (FILE_IN_CABINET_INFO)Marshal.PtrToStructure(param1, typeof(FILE_IN_CABINET_INFO));
				fileInCabinetInfo.FullTargetName = this.targetPath + fileInCabinetInfo.NameInCabinet;
				Marshal.StructureToPtr(fileInCabinetInfo, param1, true);

				returnValue = (uint)FILEOP.FILEOP_DOIT;
			}
			return returnValue;
		}
		
		public delegate uint PSP_FILE_CALLBACK(uint context, uint notification, IntPtr param1, IntPtr param2);

		[DllImport("SetupApi.dll", CharSet=CharSet.Auto)]
		public static extern bool SetupIterateCabinet(string cabinetFile, uint reserved, PSP_FILE_CALLBACK callBack, uint context);

		public const uint NO_ERROR = 0;
		public const uint SPFILENOTIFY_FILEINCABINET = 0x00000011;
		public const uint SPFILENOTIFY_FILEEXTRACTED = 0x00000013;
		public const uint FILEOP_DOIT = 1;
		
		[DllImport("Kernel32.dll", CharSet=CharSet.Auto)]
		public static extern uint GetLastError();
	}

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    class FILE_IN_CABINET_INFO
    {
        public String NameInCabinet;
        public uint FileSize;
        public uint Win32Error;
        public ushort DosDate;
        public ushort DosTime;
        public ushort DosAttribs;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public System.String FullTargetName;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    class FILEPATHS
    {
        public String Target;
        public String Source;
        public uint Win32Error;
        public uint Flags;
    }

    enum SetupIterateCabinetAction : uint
    {
        Iterate = 0, Extract
    }

    enum FILEOP : uint
    {
        FILEOP_ABORT = 0,
        FILEOP_DOIT,
        FILEOP_SKIP
    }
}
